package com.yj.auto.core.jfinal.interceptor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.hibernate.validator.constraints.Length;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.yj.auto.Constants;
import com.yj.auto.core.base.annotation.Valid;
import com.yj.auto.core.base.model.ResponseModel;
import com.yj.auto.core.base.model.ValidResult;
import com.yj.auto.core.jfinal.base.BaseController;

/**
 * 参数校验拦截器
 */
public class ValidatorInterceptor implements Interceptor {
	private static final Log logger = Log.getLog(ValidatorInterceptor.class);
	private static ValidatorInterceptor interceptor = null;
	private Validator validator = null;

	private ValidatorInterceptor() {
		ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
		validator = factory.getValidator();
	}

	public Validator getValidator() {
		return validator;
	}

	public static ValidatorInterceptor me() {
		if (null == interceptor) {
			interceptor = new ValidatorInterceptor();
		}
		return interceptor;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void intercept(Invocation inv) {
		boolean success = true;
		if (null != validator) {
			BaseController controller = (BaseController) inv.getController();
			Method[] methods = controller.getClass().getDeclaredMethods();// 获取controller类里所有声明的方法
			for (Method method : methods) {
				if (!inv.getActionKey().endsWith("/" + method.getName()))
					continue;// 找到当前请求所调用的方法，方法名不对应，不验证
				Valid valid = method.getAnnotation(Valid.class);
				if (valid == null)
					continue;
				Class<?> cls = valid.type();// 获取需要校验的java bean 类型
				String model = valid.model();
				Class<?>[] groups = valid.groups();
				Object bean = controller.getBean(cls, model);
				if (null == bean)
					continue;
				List<ValidResult> error = validate(bean, groups, valid.model());
				success = error.size() < 1;
				if (!success) {// ajax请求，返回json对象
					ResponseModel<List<ValidResult>> res = new ResponseModel<List<ValidResult>>(false);
					res.setData(error);
					controller.renderJson(res);
					logger.warn("验证失败：" + method.getName());
					return;
				}
			}
		}
		if (success) {// 没有错误就放行
			inv.invoke();
		}
	}

	public List<ValidResult> validate(Object bean, Class<?>[] groups, String modelPrefix) {
		List<ValidResult> error = new ArrayList<ValidResult>();
		Set<ConstraintViolation<Object>> constraintViolations = null;
		if (groups != null && groups.length > 0) {// 支持分组校验
			constraintViolations = validator.validate(bean, groups);
		} else {
			constraintViolations = validator.validate(bean);
		}
		if (null == constraintViolations || constraintViolations.isEmpty()) {
			return error;
		}
		ToStringBuilder sb = new ToStringBuilder(bean, ToStringStyle.MULTI_LINE_STYLE);
		for (ConstraintViolation obj : constraintViolations) {
			Annotation annot = obj.getConstraintDescriptor().getAnnotation();
			String type = annot.annotationType().getSimpleName();
			String id = modelPrefix + "." + obj.getPropertyPath().toString();
			String msg = obj.getMessage();
			if (StrKit.isBlank(msg)) {// msg有默认值，直接使用就好
				// 以下代码无效
				msg = Constants.VALID_NOT_NULL;// 默认为必填提醒
				if (annot instanceof Length) {// 暂时只验证最大长度
					String max = String.valueOf(((Length) annot).max());
					msg = Constants.VALID_MAX_LEN.replace("%s", max);
				}
			}
			error.add(new ValidResult(id, type, msg));
			sb.append(id, msg);
		}
		if (error.size() > 0) {
			logger.warn("验证[" + bean.getClass().getName() + "]失败：" + sb);
		}
		return error;
	}
}
